/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.sensor.area;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import java.util.List;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import nl.cloudfarming.client.model.Field;
import nl.cloudfarming.client.model.SensorData;
import nl.cloudfarming.client.model.SensorDataFile;
import nl.cloudfarming.client.model.SensorRun;
import nl.cloudfarming.client.sensor.SensorService;
import org.openide.util.lookup.ServiceProvider;

/**
 *
 * @author Timon Veenstra
 */
@ServiceProvider(service = SensorAreaService.class)
public class SensorAreaService extends SensorService {

    @Override
    protected String getModuleName() {
        return SensorAreaModule.MODULE_NAME;
    }

    public void persist(List<SensorData> sensorData) {
            startTransaction();
            for (SensorData sd : sensorData) {
                merge(sd);
            }
            commit();
            getEntityManager().clear();
    }

    /**
     * Finds unlinked sensor data in a box by evaluating
     * minx <= longitude <= maxx
     * and
     * miny <= latitude <= maxy
     *
     * @param minx
     * @param maxx
     * @param miny
     * @param maxy
     * @return list with unlinked sensor data that where int the box
     */
    public List<SensorData> findUnlinkedSensorDataInBox(Geometry box) {
        startTransaction();

        Coordinate firstPoint = box.getCoordinate();
        double minx = firstPoint.x;
        double maxx = firstPoint.x;
        double miny = firstPoint.y;
        double maxy = firstPoint.y;

        // Get bounds
        for (Coordinate c : box.getCoordinates()) {
            minx = (minx > c.x) ? c.x : minx;
            maxx = (maxx < c.x) ? c.x : maxx;
            miny = (miny > c.y) ? c.y : miny;
            maxy = (maxy < c.y) ? c.y : maxy;
        }

        Query query = getEntityManager().createQuery("select s from SensorData s "
                + "where s.sensorRun is null "
                + "and s.longitude <= :maxx "
                + "and s.longitude >= :minx "
                + "and s.latitude <= :maxy "
                + "and s.latitude >= :miny ");
        query.setParameter("minx", minx);
        query.setParameter("maxx", maxx);
        query.setParameter("miny", miny);
        query.setParameter("maxy", maxy);
        List<SensorData> result = query.getResultList();

        return result;
    }

    public void newSensorRun(SensorRun sensorRun) {
        persistInTransaction(sensorRun);
    }

    public SensorRun findSensorRunForPlotAndFile(Field field, SensorDataFile<?> sensorDataFile) {
        startTransaction();
        Query query = getEntityManager().createQuery(
                "select sr from SensorRun sr "
                + "where sr.sensorDataFile = :sensorDataFile "
                + "and sr.field = :field");
        query.setParameter("sensorDataFile", sensorDataFile);
        query.setParameter("field", field);
        try {
            return (SensorRun) query.getSingleResult();
        } catch (NoResultException ner) {
            return null;
        }
    }

    public List<SensorData> findSensorDataForPlot(Field field) {
        startTransaction();
        Query query = getEntityManager().createQuery(
                "select sd from SensorData sd "
                + "where sd.sensorRun in "
                + "(select sr from SensorRun sr, SensorDataFile sdf "
                + "where sdf = sr.sensorDataFile "
                + "and sr.field = :field)");
        query.setParameter("field", field);
        try {
            return (List<SensorData>) query.getResultList();
        } catch (NoResultException ner) {
            return null;
        }
    }
}
